#pragma once
#include <iostream>
#include <QDebug>
#include <memory>
#include <QJsonObject>
#include <QJsonDocument>
#include <QString>

enum Code
{
    Error = -1,
    Success = 0,
    AlreadyRegistered,
    AlreadyLogged,
    UserDoesNotExist,
    PasswordError,

};


class Protocol;
class ProtocolLoginReq;
class ProtocolRegisterReq;
class ProtocolCommonResp;

using ProtocolPtr = std::shared_ptr<Protocol>;
using ProtocolLoginReqPtr = std::shared_ptr<ProtocolLoginReq>;
using ProtocolRegisterReqPtr = std::shared_ptr<ProtocolRegisterReq>;
using ProtocolCommonRespPtr = std::shared_ptr<ProtocolCommonResp>;

class Protocol
{
public:
    enum Type
    {
        UnKnown = 0,
        CommonResp,
        LoginReq,
        RegisterReq,

        Max,

    };

    Protocol(Type type)
        : _type(type)
    {
    }

    virtual QString serialize() = 0;
    virtual void deserialize(const QJsonObject &) = 0;

    Protocol::Type getType()
    {
        return _type;
    }

    static bool isValidProtocolType(int value)
    {
        constexpr int min = (int)(Protocol::Type::UnKnown);
        constexpr int max = (int)(Protocol::Type::Max);
        return value > min && value < max;
    }

    virtual ~Protocol() {}

    Type _type;
};

class ProtocolLoginReq : public Protocol
{
public:
    ProtocolLoginReq()
        : Protocol(Type::LoginReq)
    {
    }

    virtual QString serialize() override
    {
        QJsonObject json;
        json["type"] = _type;
        json["username"] = userid;
        json["password"] = password;

        QJsonDocument doc(json);
        return doc.toJson(QJsonDocument::Compact);
    }
    virtual void deserialize(const QJsonObject &obj) override
    {
        _type = (Protocol::Type)obj["type"].toInt();
        userid = obj["username"].toString();
        password = obj["password"].toString();
    }

    QString getUserid()
    {
        return userid;
    }

    QString getPassword()
    {
        return password;
    }

    void setUserid(QString username)
    {
        this->userid = username;
    }

    void setPassword(QString password)
    {
        this->password = password;
    }

private:
    QString userid;
    QString password;
};

class ProtocolRegisterReq : public Protocol
{
public:
    ProtocolRegisterReq()
        : Protocol(Type::RegisterReq)
    {
    }

    virtual QString serialize() override
    {
        QJsonObject json;
        json["type"] = _type;
        json["username"] = username;
        json["userid"] = userid;
        json["password"] = password;
        json["head"] = head;

        QJsonDocument doc(json);
        return doc.toJson(QJsonDocument::Compact);
    }
    virtual void deserialize(const QJsonObject &obj) override
    {
        _type = (Protocol::Type)obj["type"].toInt();
        username = obj["username"].toString();
        userid = obj["userid"].toString();
        password = obj["password"].toString();
        head = obj["head"].toString();
    }

    QString getUsername()
    {
        return username;
    }

    QString getPassword()
    {
        return password;
    }

    QString getHead()
    {
        return head;
    }

    void setUsername(QString username)
    {
        this->username = username;
    }

    void setPassword(QString password)
    {
        this->password = password;
    }

    QString getUserid()
    {
        return userid;
    }

    void setUserid(const QString& userid)
    {
        this->userid = userid;
    }

    void setHead(const QString& head)
    {
        this->head = head;
    }
private:
    QString username;
    QString userid;
    QString password;
    QString head;
};

// 服务端会返回的一个通用响应模块
class ProtocolCommonResp : public Protocol
{
public:
    ProtocolCommonResp()
        : Protocol(Type::CommonResp)
    {
    }

    virtual QString serialize() override
    {
        QJsonObject json;
        json["type"] = _type;
        json["code"] = code;

        QJsonDocument doc(json);
        return doc.toJson(QJsonDocument::Compact);
    }
    virtual void deserialize(const QJsonObject &obj) override
    {
        _type = (Protocol::Type)obj["type"].toInt();
        code = (Code)obj["code"].toInt();
    }

    void setCode(Code code)
    {
        this->code = code;
    }

    int getCode()
    {
        return code;
    }

private:
    Code code;
};

// 工厂类，用于创建不同类型的协议对象
class ProtocolFactory
{
public:
    static ProtocolPtr createProtocol(Protocol::Type type)
    {
        switch (type)
        {
        case Protocol::LoginReq:
            return std::make_shared<ProtocolLoginReq>();
        case Protocol::RegisterReq:
            return std::make_shared<ProtocolRegisterReq>();
        case Protocol::CommonResp:
            return std::make_shared<ProtocolCommonResp>();
        default:
            return nullptr;
        }
    }

    static ProtocolPtr createProtocolFromJson(const QString &json)
    {
        QJsonDocument doc = QJsonDocument::fromJson(json.toUtf8());
        if (!doc.isObject())
        {
            qDebug() << "解析json错误";
             return nullptr;
        }

        QJsonObject obj = doc.object();
        Protocol::Type type = (Protocol::Type)(obj["type"].toInt());

//        qDebug() << "协议类型：" << obj["type"] << " " << json << " " << type;

        ProtocolPtr ret = createProtocol(type);
        if(ret != nullptr)
            ret->deserialize(obj);

        return ret;
    }
};


